package com.game.core.dbwrite.domain;

import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.game.core.dbwrite.constant.DBOperationType;
import com.game.core.dbwrite.server.DBServiceParemeter;
import com.game.core.dbwrite.util.WriteToDBUtil;

public class MemoryCache
{
	private static final Logger logger = LoggerFactory.getLogger(MemoryCache.class);
	private static Map<Long, StoreEntity> map1 = new TreeMap<Long, StoreEntity>(new Comparator<Long>()
	{
		@Override
		public int compare(Long o1, Long o2)
		{
			return (int) (o1 - o2);
		}
	});
	private static Map<Long, StoreEntity> map2 = new TreeMap<Long, StoreEntity>(new Comparator<Long>()
	{
		@Override
		public int compare(Long o1, Long o2)
		{
			return (int) (o1 - o2);
		}
	});
	private static final ReadWriteLock lock1 = new ReentrantReadWriteLock(false);
	private static final ReadWriteLock lock2 = new ReentrantReadWriteLock(false);

	private static volatile boolean exchange = true;    // 交替向Map中写数据标志

	public static void addToMap(long beanNum, Class<?> clazz, DBOperationType type, byte[] b)
	{
		if (exchange)
		{
			//这里由读锁，修改成了写锁
			lock1.writeLock().lock();
			try
			{
				StoreEntity entity = new StoreEntity(clazz, type, b);
				map1.put(beanNum, entity);
			}
			catch (Exception e)
			{
				logger.error("addToMap error: ", e);
			}
			finally
			{
				lock1.writeLock().unlock();
			}
		}
		else
		{
			//这里由读锁，修改成了写锁
			lock2.writeLock().lock();
			try
			{
				StoreEntity entity = new StoreEntity(clazz, type, b);
				map2.put(beanNum, entity);
			}
			catch (Exception e)
			{
				logger.error("addToMap error: ", e);
			}
			finally
			{
				lock2.writeLock().unlock();
			}
		}
	}

	public static void writeToDatabase()
	{
		int count = DBServiceParemeter.WRITE_TO_DB_ITEM;
		if (exchange)
		{
			try
			{
				lock1.writeLock().lock();
				exchange = false;
				Iterator<Entry<Long, StoreEntity>> iter = map1.entrySet().iterator();
				while (iter.hasNext() && count-- > 0)
				{
					Map.Entry<Long, StoreEntity> entry = iter.next();
					WriteToDBUtil.writeStoreEntityToDB(entry.getValue());
					iter.remove();
				}
				//map1.clear();
			}
			catch (Exception e)
			{
				logger.error("writeToDatabase error ",e);
			}
			finally
			{
				lock1.writeLock().unlock();
			}
		}
		else
		{
			try
			{
				lock2.writeLock().lock();
				exchange = true;
				Iterator<Entry<Long, StoreEntity>> iter = map2.entrySet().iterator();
				while (iter.hasNext() && count-- > 0)
				{
					Map.Entry<Long, StoreEntity> entry = iter.next();
					WriteToDBUtil.writeStoreEntityToDB(entry.getValue());
					iter.remove();
				}
				//map2.clear();
			}
			catch (Exception e)
			{
				logger.error("writeToDatabase error ",e);
			}
			finally
			{
				lock2.writeLock().unlock();
			}
		}
//		logger.debug("writeToDatabase: count is " + count);
	}

	public static boolean isMemoryFinishedWriting()
	{
		return (map1.isEmpty() && map2.isEmpty());
	}

	public static void writeToRocksDB()
	{
		if (exchange)
		{
			lock1.writeLock().lock();
			try
			{
				exchange = false;
				Iterator<Entry<Long, StoreEntity>> iter = map1.entrySet().iterator();
				while (iter.hasNext())
				{
					Map.Entry<Long, StoreEntity> entry = iter.next();
					Storage.addToList(entry.getKey(), entry.getValue());
					logger.info("Write key " + entry.getKey() + " to RocksDB.");
				}
				map1.clear();
			}
			catch (Exception e)
			{
				logger.error("writeToRocksDB error ",e);
			}
			finally
			{
				lock1.writeLock().unlock();
			}
		}
		else
		{
			lock2.writeLock().lock();
			try
			{
				exchange = true;
				Iterator<Entry<Long, StoreEntity>> iter = map2.entrySet().iterator();
				while (iter.hasNext())
				{
					Map.Entry<Long, StoreEntity> entry = iter.next();
					Storage.addToList(entry.getKey(), entry.getValue());
					logger.info("Write key " + entry.getKey() + " to RocksDB.");
				}
				map2.clear();
			}
			catch (Exception e)
			{
				logger.error("writeToRocksDB error ",e);
			}
			finally
			{
				lock2.writeLock().unlock();
			}
		}
	}

	public static void dumpMap()
	{
		logger.info("map1 content is:");
		if(map1 != null && map1.isEmpty())
			logger.info("map1 is null.");
		else
			for (Map.Entry<Long, StoreEntity> entry : map1.entrySet())
				logger.info("[key] = " + entry.getKey() + ", [value] = " + entry.getValue().getClazz().getName());

		logger.info("map2 content is:");
		if(map1 != null && map2.isEmpty())
			logger.info("map2 is null.");
		else
			for (Map.Entry<Long, StoreEntity> entry : map2.entrySet())
				logger.info("[key] = " + entry.getKey() + ", [value] = " + entry.getValue().getClazz().getName());
	}
	
	public static int getDBMemoryCacheTaskCount()
	{
		return map1.size() + map2.size();
	}
}